package com.yxh.www.author.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yxh.www.author.domain.SmAccount;
import com.yxh.www.author.dto.SmAccountToken;
import com.yxh.www.author.mapper.SmAccountMapper;
import com.yxh.www.author.mapper.SmServerApiMapper;
import com.yxh.www.author.service.SmAccountService;
import com.yxh.www.common.constant.Constant;
import com.yxh.www.common.result.Result;
import com.yxh.www.common.result.ResultBuilder;
import com.yxh.www.common.result.ResultEnum;
import com.yxh.www.common.util.JwtTokenUtil;
import com.yxh.www.common.util.MapBeanUtil;
import com.yxh.www.mysql.base.BaseServiceImpl;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 系统第三方授权信息 服务实现类
 * </p>
 *
 * @author Yangxiaohui
 * @since 2020-05-09
 */
@Service
public class SmAccountServiceImpl extends BaseServiceImpl<SmAccountMapper, SmAccount> implements SmAccountService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final StringRedisTemplate stringRedisTemplate;
    private final SmServerApiMapper smServerApiMapper;

    public SmAccountServiceImpl(RedisTemplate<String, Object> redisTemplate, StringRedisTemplate stringRedisTemplate, SmServerApiMapper smServerApiMapper) {
        this.redisTemplate = redisTemplate;
        this.stringRedisTemplate = stringRedisTemplate;
        this.smServerApiMapper = smServerApiMapper;
    }

    /**
     * 新增系统第三方账户
     *
     * @param accountName 账户名   必填
     * @param remark      账户备注  非必填
     * @param scopeIp     可访问IP域    必填
     * @param userId      用户ID  必填
     * @return 统一响应 {@link Result}
     */
    @Override
    public Result<Object> addSmAccount(String accountName, String remark, String scopeIp, String userId) {
        int countSmAccountByAccountNameAndUserId = baseMapper.selectCount(new QueryWrapper<SmAccount>()
                .eq("account_name", accountName)
                .eq("user_id", userId)
        );
        if (countSmAccountByAccountNameAndUserId > 0) {
            return ResultBuilder.error(ResultEnum.USER_HANDEL_ERROR, "账户名重复！");
        }
        SmAccount smAccount = new SmAccount(accountName, remark, scopeIp, userId);
        // 生成秘钥
        smAccount.setSecretKey(DigestUtils.md5Hex(accountName + userId));
        smAccount.setCreateTime(LocalDateTime.now());
        return smAccount.insert() ? ResultBuilder.success() : ResultBuilder.error(ResultEnum.USER_HANDEL_ERROR, "新增账户失败");
    }

    /**
     * 修改系统第三方账户
     *
     * @param id            账户ID    必填
     * @param accountStatus 账户状态 （0：正常；1：失效）
     * @param remark        备注
     * @param scopeIp       可访问IP域    必填
     * @return 统一响应 {@link Result}
     */
    @Override
    public Result<Object> modifySmAccount(String id, String accountStatus, String remark, String scopeIp) {
        SmAccount smAccount = new SmAccount()
                .setId(id)
                .setAccountStatus(accountStatus)
                .setRemark(remark)
                .setScopeIp(scopeIp);
        return smAccount.updateById() ? ResultBuilder.success() : ResultBuilder.error(ResultEnum.USER_HANDEL_ERROR, "修改失败！");
    }

    /**
     * 根据ID删除系统第三方账户
     *
     * @param ids 账户ID集合
     * @return 统一响应 {@link Result}
     */
    @Override
    public Result<Object> removeSmAccount(String[] ids) {
        baseMapper.deleteBatchIds(Arrays.asList(ids));
        return ResultBuilder.success();
    }

    /**
     * 查询系统应用列表
     *
     * @param accountName 应用名称 模糊匹配
     * @param userId      用户ID 精准匹配
     * @return 统一响应 {@link Result<  List  >} 实体 {@link SmAccount}
     */
    @Override
    public Result<List<SmAccount>> listSmAccount(String accountName, String userId) {
        QueryWrapper<SmAccount> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(accountName)) {
            queryWrapper.eq("account_name", accountName);
        }
        if (StringUtils.isNotBlank(userId)) {
            queryWrapper.eq("user_id", userId);
        }
        return ResultBuilder.success(baseMapper.selectList(queryWrapper));
    }

    /**
     * 分页查询系统应用列表
     *
     * @param accountName 应用名称 模糊匹配
     * @param userId      用户ID 精准匹配
     * @param pageNum     页码          默认值 1
     * @param pageSize    页面数据长度    默认值 20
     * @return 统一响应 {@link Result}
     */
    @Override
    public Result<Object> pageSmAccount(String accountName, String userId, Long pageNum, Long pageSize) {
        QueryWrapper<SmAccount> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(accountName)) {
            queryWrapper.eq("account_name", accountName);
        }
        if (StringUtils.isNotBlank(userId)) {
            queryWrapper.eq("user_id", userId);
        }
        return ResultBuilder.success(baseMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper));
    }

    /**
     * 第三方应用获取Token
     *
     * @param userId      所属用户ID  必填
     * @param accountName 应用名称    必填
     * @param secretKey   私钥  必填
     * @return 统一响应 {@link Result}
     */
    @Override
    public Result<Object> authorSmAccount(String userId, String accountName, String secretKey) {
        SmAccount smAccount = baseMapper.selectOne(new QueryWrapper<SmAccount>()
                .eq("user_id", userId)
                .eq("account_name", accountName)
                .eq("secret_key", secretKey)
        );
        if (smAccount == null || StringUtils.isBlank(smAccount.getId())) {
            return ResultBuilder.error(ResultEnum.USER_HANDEL_ERROR, "应用授权失败，不正确的应用参数！");
        }
        // Token有效期 一天=24小时
        long ttlMillis = 31557600000L;
        // 生成应用Token
        String token = JwtTokenUtil.buildToken(smAccount.getId(), JwtTokenUtil.TokenType.SDK_Client_TOKEN, ttlMillis, MapBeanUtil.object2Map(smAccount));
        // 放入可请求地址 - 精准匹配
        Set<String> apiPath = smServerApiMapper.listSmAccountApiSetString(smAccount.getId(), 0);
        // 放入PathValue 模糊匹配地址
        Set<String> pathValueApiPath = smServerApiMapper.listSmAccountApiSetString(smAccount.getId(), 1);
        // 放入可请求域
        String accountScopeIp=smAccount.getScopeIp();
        // 放入Redis Token
        SmAccountToken smAccountToken = new SmAccountToken(smAccount.getId(), smAccount.getAccountName(), token, apiPath, pathValueApiPath,smAccount.getScopeIp());
        redisTemplate.opsForValue().set(Constant.REDIS_ACCOUNT_TOKEN_KEY + token, smAccountToken, ttlMillis, TimeUnit.MILLISECONDS);
        // 返回Token
        return ResultBuilder.success(smAccountToken);
    }
}
